# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: reporter\reports\basic_template.py
import io, urllib, urllib.parse, tempfile
from io import StringIO
from cvsslib import CVSS3State, CVSS2State
from cvsslib.vector import VectorError
from xml.sax.saxutils import escape
from http.server import BaseHTTPRequestHandler
import re, datetime, unicodedata


class ReportAbortedException(Exception):
    pass


class ReportTemplate:
    SEVERITY_MAX = 3

    def __init__(self, sources):
        self.sources = sources
        self.aborted = False
        self.progress = 0

    def abort(self):
        self.aborted = True

    def check_aborted(self):
        if self.aborted:
            raise ReportAbortedException()

    def parts(self):
        self.progress = 100
        yield

    def write_parts(self, stream):
        for part in self.parts():
            if isinstance(part, str):
                try:
                    stream.write(part)
                except UnicodeEncodeError:
                    stream.write(self.normalize_encoding(part))

            else:
                if hasattr(part, "read"):
                    while 1:
                        p = part.read(1048576)
                        l = len(p)
                        if l:
                            try:
                                stream.write(p)
                            except UnicodeEncodeError:
                                stream.write(self.normalize_encoding(part))

                            if l < 1048576:
                                break

            if self.aborted:
                break

    def generate_report(self, output):
        try:
            if isinstance(output, str):
                with open(output, "w+", encoding="utf-8") as (stream):
                    self.write_parts(stream)
            else:
                if isinstance(output, io.IOBase):
                    self.write_parts(output)
        except ReportAbortedException:
            return

    @staticmethod
    def remove_blank_lines(string_to_process):
        result = string_to_process.replace("\r", "")
        result = ("").join([s for s in result.splitlines(True) if s.strip("\r\n")])
        return result

    def escape_html(self, string_to_escape):
        html_escape_table = {'"': "&quot;", "'": "&apos;"}
        result = escape(string_to_escape, html_escape_table)
        return self.remove_blank_lines(result)

    @staticmethod
    def normalize_encoding(string_to_normalize):
        if isinstance(string_to_normalize, bytes) or string_to_normalize is None:
            return string_to_normalize
        else:
            intermediate_string = string_to_normalize
            if isinstance(string_to_normalize, StringIO):
                intermediate_string = string_to_normalize.getvalue()
            encoded_string = unicodedata.normalize("NFKD", intermediate_string).encode(
                "utf-8", errors="replace"
            )
            return encoded_string.decode("utf-8", errors="replace")

    @staticmethod
    def get_severity_string(severity_int):
        if severity_int == 0:
            return "Informational"
        if severity_int == 1:
            return "Low"
        if severity_int == 2:
            return "Medium"
        if severity_int == 3:
            return "High"

    def get_classifications(self, vulnerability_type, should_decode_cvss_vector=True):
        classifications = []
        if "cvss2" in vulnerability_type:
            if vulnerability_type["cvss2"]:
                cvss_value = vulnerability_type["cvss2"]
                if should_decode_cvss_vector:
                    cvss_value = self.decode_cvss(vulnerability_type["cvss2"], "cvss2")
                classifications.append({"type": "CVSS2", "details": cvss_value})
        if "cvss3" in vulnerability_type:
            if vulnerability_type["cvss3"]:
                cvss_value = vulnerability_type["cvss3"]
                if should_decode_cvss_vector:
                    cvss_value = self.decode_cvss(vulnerability_type["cvss3"], "cvss3")
                classifications.append({"type": "CVSS3", "details": cvss_value})
        for tag in vulnerability_type["tags"]:
            if tag.startswith("CVE"):
                classifications.append({"type": "CVE", "details": tag})
            if tag.startswith("CWE"):
                classifications.append({"type": "CWE", "details": tag})

        return classifications

    def decode_cvss(self, cvss_string, version):
        BASE_SCORE = "Base Score: "
        ATTACK_VECTOR = "Attack Vector: "
        ATTACK_COMPLEXITY = "Attack Complexity: "
        PRIVILEGES_REQUIRED = "Privileges Required: "
        USER_INTERACTION = "User Interaction: "
        SCOPE = "Scope: "
        CONFIDENTIALITY_IMPACT = "Confidentiality Impact: "
        INTEGRITY_IMPACT = "Integrity Impact: "
        AVAILABILITY_IMPACT = "Availability Impact: "
        ACCESS_VECTOR = "Access Vector: "
        ACCESS_COMPLEXITY = "Access Complexity: "
        AUTHENTICATION = "Authentication: "
        EXPLOITABILITY = "Exploitability: "
        REMEDIATION_LEVEL = "Remediation Level: "
        REPORT_CONFIDENCE = "Report Confidence: "
        AVAILABILITY_REQUIREMENT = "Availability Requirement: "
        COLLATERAL_DAMAGE_POTENTIAL = "Collateral Damage Potential: "
        CONFIDENTIALITY_REQUIREMENT = "Confidentiality Requirement: "
        INTEGRITY_REQUIREMENT = "Integrity Requirement: "
        TARGET_DISTRIBUTION = "Target Distribution: "
        detailed_string = ""
        cvss_string = cvss_string.strip()
        if version == "cvss3":
            state = CVSS3State()
            state.from_vector(cvss_string)
            try:
                scores = state.calculate()
                detailed_string += BASE_SCORE + str(scores[0]) + "<br>\n"
                detailed_string += (
                    ATTACK_VECTOR + state.attack_vector.name.capitalize() + "<br>\n"
                )
                detailed_string += (
                    ATTACK_COMPLEXITY
                    + state.attack_complexity.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    PRIVILEGES_REQUIRED
                    + state.privilege_required.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    USER_INTERACTION
                    + state.user_interaction.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += SCOPE + state.scope.name.capitalize() + "<br>\n"
                detailed_string += (
                    CONFIDENTIALITY_IMPACT
                    + state.confidentiality_impact.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    INTEGRITY_IMPACT
                    + state.integrity_impact.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    AVAILABILITY_IMPACT
                    + state.availability_impact.name.capitalize()
                    + "<br>\n"
                )
            except VectorError:
                pass

        else:
            state = CVSS2State()
            state.from_vector(cvss_string)
            try:
                scores = state.calculate()
                detailed_string += BASE_SCORE + str(scores[0]) + "<br>\n"
                detailed_string += (
                    ACCESS_VECTOR + state.access_vector.name.capitalize() + "<br>\n"
                )
                detailed_string += (
                    ACCESS_COMPLEXITY
                    + state.access_complexity.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    AUTHENTICATION + state.authentication.name.capitalize() + "<br>\n"
                )
                detailed_string += (
                    CONFIDENTIALITY_IMPACT
                    + state.confidentiality_impact.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    INTEGRITY_IMPACT
                    + state.integrity_impact.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    AVAILABILITY_IMPACT
                    + state.availability_impact.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    EXPLOITABILITY + state.exploitability.name.capitalize() + "<br>\n"
                )
                detailed_string += (
                    REMEDIATION_LEVEL
                    + state.remediation_level.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    REPORT_CONFIDENCE
                    + state.report_confidence.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    AVAILABILITY_REQUIREMENT
                    + state.availability_requirement.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    COLLATERAL_DAMAGE_POTENTIAL
                    + state.collateral_damage_potential.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    CONFIDENTIALITY_REQUIREMENT
                    + state.confidentiality_requirement.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    INTEGRITY_REQUIREMENT
                    + state.integrity_requirement.name.capitalize()
                    + "<br>\n"
                )
                detailed_string += (
                    TARGET_DISTRIBUTION
                    + state.target_distribution.name.capitalize()
                    + "<br>\n"
                )
            except VectorError:
                pass

            return detailed_string

    @staticmethod
    def unquote_url(encoded_string):
        return urllib.parse.unquote(encoded_string)

    def get_well_formed_scan_info(self, source):
        scan_info = source.info()
        if "duration" in scan_info:
            if scan_info["duration"]:
                duration_seconds = int(scan_info["duration"].total_seconds())
                minutes = duration_seconds // 60
                minutes_string = str(minutes) + " minutes, " if minutes > 0 else ""
                scan_info["duration"] = (
                    minutes_string + str(duration_seconds % 60) + " seconds"
                )
        if "start_date" in scan_info:
            if scan_info["start_date"]:
                scan_info["start_date"] = self.get_formatted_date(
                    scan_info["start_date"]
                )
        if "end_date" in scan_info:
            if scan_info["end_date"]:
                scan_info["end_date"] = self.get_formatted_date(scan_info["end_date"])
        if hasattr(source, "scan_info"):
            if "status" in source.scan_info:
                if source.scan_info["status"]:
                    scan_info["aborted"] = (
                        "True" if source.scan_info["status"] == "aborted" else "False"
                    )
        if hasattr(source, "scan_info"):
            scan_info["scan_status"] = source.scan_info.get("status")
        return scan_info

    @staticmethod
    def get_formatted_date(date):
        return date.strftime("%d/%m/%Y, %H:%M:%S")

    @staticmethod
    def get_formatted_nowdate():
        now_date = datetime.datetime.now()
        return now_date.strftime("%d %B %Y")

    def get_request_parts(self, request_txt):
        class HTTPRequest(BaseHTTPRequestHandler):
            def __init__(self, request_text):
                self.rfile = io.BytesIO(request_text.encode("iso-8859-1", "ignore"))
                self.raw_requestline = self.rfile.readline()
                self.error_code = self.error_message = None
                self.parse_request()

            def send_error(self, code, message):
                self.error_code = code
                self.error_message = message

        result = dict()
        request = HTTPRequest(request_txt)
        result["request_type"] = request.command
        if hasattr(request, "path"):
            result["parameters"] = self.get_parameters_from_url_path(request.path)
        return result

    def get_parameters_from_url_path(self, path):
        result = dict()
        match = re.match("[^?]*\\?(.*)", path)
        if match:
            for parameter in match.group(1).split("&"):
                match2 = re.match("([^=]*)=([^&]*)", parameter)
                if match2:
                    result[match2.group(1)] = self.normalize_encoding(match2.group(2))

        return result

    def calculate_threat_level(self, alerts_count):
        threat_level = 0
        if alerts_count[self.SEVERITY_MAX - 2] > 0:
            threat_level = 1
        if alerts_count[self.SEVERITY_MAX - 1] > 0:
            threat_level = 2
        if alerts_count[self.SEVERITY_MAX] > 0:
            threat_level = 3
        return threat_level

    @staticmethod
    def generate_link(link_id):
        return "link_id_" + str(link_id).replace(" ", "_")


class NamedTempFileWithNormalizedWrite:
    def __init__(self):
        self.tempFile = tempfile.NamedTemporaryFile(
            mode="w+", delete=True, encoding="utf-8"
        )

    def __enter__(self):
        self.__init__()
        return self

    def __exit__(self, exc, value, tb):
        self.tempFile.close()

    def write(self, string):
        try:
            self.tempFile.write(string)
        except UnicodeEncodeError:
            self.tempFile.write(ReportTemplate.normalize_encoding(string))

    def truncate(self):
        self.tempFile.truncate()

    def seek(self, pos):
        self.tempFile.seek(pos)

    def read(self, amount=0):
        if amount == 0:
            return self.tempFile.read()
        else:
            return self.tempFile.read(amount)
